﻿/******************************************************************************
 * This file is part of libemb.
 *
 * libemb is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * libemb is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with libemb.  If not, see <http://www.gnu.org/licenses/>.
 *
 * Project: Embedme
 * Author : FergusZeng
 * Email  : cblock@126.com
 * git	  : https://git.oschina.net/cblock/embedme
 * Copyright 2014~2017 @ ShenZhen ,China
*******************************************************************************/
#include "RtcFacade.h"
#include "Tracer.h"

#include <stdio.h>
#include <unistd.h>
#include <time.h>
#include <sys/ioctl.h>
#include <sys/time.h>
#include <sys/types.h>
#include <fcntl.h>
#include <time.h>

#if defined(OS_CYGWIN) || defined(OS_ANDROID)
#define USE_RTC     0
#else
#include <linux/rtc.h>
#define RTC_DEV_PATH    "/dev/rtc0"
#define USE_RTC     1
#endif

namespace libemb{
RtcFacade::RtcFacade()
{
}

RtcFacade::~RtcFacade()
{
}

/**
 *  \brief  显示实时时间
 *  \param  rtcTime 时间结构体
 *  \return void
 *  \note   none
 */
void RtcFacade::showTime(RtcTime_S rtcTime)
{
	printf("******************************************************\n");
    printf("the RTC time is:\n");
    printf("%d.%d.%d-%d:%d:%d\n", rtcTime.m_year, rtcTime.m_month, rtcTime.m_date, rtcTime.m_hour, rtcTime.m_minute, rtcTime.m_second);
    printf("******************************************************\n");
}

/**
 *  \brief  获取实时时间
 *  \param  rtcTime 时间结构体
 *  \return 成功返回STATUS_OK,失败返回STATUS_ERROR
 *  \note   none
 */
int RtcFacade::readTime(RtcTime_S & rtcTime)
{
#if USE_RTC
	int rtcFd=::open(RTC_DEV_PATH,O_RDWR);
    if (rtcFd<0)
    {
        TRACE_ERR_CLASS("open rtc error:%s.\n",ERROR_STRING);
        return STATUS_ERROR;
    }
    struct rtc_time rtc_tm;
    int ret=::ioctl(rtcFd, RTC_RD_TIME, &rtc_tm);
    if (ret<0)
    {
        TRACE_ERR_CLASS("read rtc error:%s.\n",ERROR_STRING);
        close(rtcFd);
        return STATUS_ERROR;    
    }
    rtcTime.m_date = rtc_tm.tm_mday;
    rtcTime.m_month = rtc_tm.tm_mon+1; 
    rtcTime.m_year = rtc_tm.tm_year+1900;
    rtcTime.m_hour = rtc_tm.tm_hour;
    rtcTime.m_minute = rtc_tm.tm_min; 
    rtcTime.m_second = rtc_tm.tm_sec;
    close(rtcFd);
    return STATUS_OK;
#else

    time_t nowTime = ::time(NULL);
    struct tm* tmTime = gmtime(&nowTime);
    rtcTime.m_second = tmTime->tm_sec;
    rtcTime.m_minute = tmTime->tm_min;
    rtcTime.m_hour   = tmTime->tm_hour + 8;
    rtcTime.m_date   = tmTime->tm_mday;
    rtcTime.m_month  = tmTime->tm_mon + 1;
    rtcTime.m_year   = (tmTime->tm_year + 1900) %100;
    return STATUS_OK;
#endif
}
/**
 *  \brief  修改实时时间
 *  \param  rtcTime 时间结构体
 *  \return 成功返回STATUS_OK,失败返回STATUS_ERROR
 *  \note   none
 */
int RtcFacade::writeTime(RtcTime_S rtcTime)
{
#if USE_RTC
    int rtcFd=::open(RTC_DEV_PATH,O_RDWR);
    if (rtcFd<0)
    {
        TRACE_ERR_CLASS("open rtc error:%s.\n",ERROR_STRING);
        return STATUS_ERROR;
    }
    struct rtc_time rtc_tm;
    rtc_tm.tm_mday = rtcTime.m_date;
    rtc_tm.tm_mon = rtcTime.m_month-1;
    rtc_tm.tm_year = rtcTime.m_year-1900;
    rtc_tm.tm_hour = rtcTime.m_hour; 
    rtc_tm.tm_min = rtcTime.m_minute;
    rtc_tm.tm_sec = rtcTime.m_second;
    int ret=::ioctl(rtcFd, RTC_SET_TIME, &rtc_tm);
    if (ret<0)
    {
        TRACE_ERR_CLASS("write rtc error:%s.\n",ERROR_STRING);
        close(rtcFd);
        return STATUS_ERROR;    
    }
    close(rtcFd);
	return STATUS_OK;
#else
    struct tm currentTime;
    currentTime.tm_mday = rtcTime.m_date;
    currentTime.tm_mon = rtcTime.m_month-1;
    currentTime.tm_year = rtcTime.m_year-1900;
    currentTime.tm_hour = rtcTime.m_hour; 
    currentTime.tm_min = rtcTime.m_minute;
    currentTime.tm_sec = rtcTime.m_second;
    currentTime.tm_isdst = 0;
    time_t seconds = mktime(&currentTime);
    if (seconds<0) 
    {
        TRACE_ERR_CLASS("make time error.\n");
        return STATUS_ERROR;
    }
    struct timeval tv;
    struct timezone tz;
    if(gettimeofday(&tv,&tz)<0)
    {
        TRACE_ERR_CLASS("get time error.\n");
        return STATUS_ERROR;
    }
    tv.tv_sec = seconds;
    tv.tv_usec = 0;
    if(settimeofday(&tv,&tz)<0)
    {
        TRACE_ERR_CLASS("set time error.\n");
        return STATUS_ERROR;
    }
    return STATUS_OK;
#endif
}
}
